package algoWing42.controlador;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import algoWing42.modelo.Avion;
import algoWing42.modelo.Disparo;
import algoWing42.modelo.Item;
import algoWing42.modelo.Juego;
import algoWing42.modelo.ObjetoDinamico;
import algoWing42.vista.*;

import titiritero.ControladorJuego;
import titiritero.Dibujable;
import titiritero.vista.TextoDinamico;

public class ControladorAlgoWing42 extends ControladorJuego {

	private Juego modelo;
	public  HashMap<String,VistaC> vistaH;
	
	public ControladorAlgoWing42(Juego unModelo) {
		super(false);
		vistaH=new HashMap<String,VistaC>();
		this.modelo = unModelo;
		this.cargarVistas();
	}		
	
	@Override 
	public void comenzarJuego(){
		estaEnEjecucion = true;
		try{
			while(estaEnEjecucion){				
				simular();
				dibujar();
				Thread.sleep(intervaloSimulacion);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void simular() {		
		this.superficieDeDibujo.limpiar();
		this.cargarEnEspera();
		modelo.juegoVivir();
	}
	
	private void dibujar() {
		@SuppressWarnings("unchecked")
		ArrayList<Dibujable> l=(ArrayList<Dibujable>) dibujables.clone();
		Iterator<Dibujable> iterador = l.iterator();
		while(iterador.hasNext()){
			Dibujable dibujable = iterador.next();
			if(dibujable.tieneSentidoDibujar()){
				dibujable.dibujar(this.superficieDeDibujo);}
			else this.removerDibujable(dibujable);
			
		}		
		this.superficieDeDibujo.actualizar();		
	}
	
	/**
	 * Carga a dibujables los nuevos objetos creados por el modelo.
	 */
	private void cargarEnEspera(){
		LinkedList<ObjetoDinamico> ObjetosACargar=modelo.getNuevosObjetosVivos();
		@SuppressWarnings("unchecked")
		LinkedList<ObjetoDinamico> ObjetosACargarClon=(LinkedList<ObjetoDinamico>) ObjetosACargar.clone();
		Iterator<ObjetoDinamico> obj= ObjetosACargarClon.iterator();
		while (obj.hasNext()){
			ObjetoDinamico actual=obj.next();
			VistaC vista= this.vistaH.get(actual.getClass().getSimpleName());
			Dibujable nuevaV=vista.nueva();
			
			nuevaV.setPosicionable(actual);
			this.agregarDibujable(nuevaV);			
		}
		modelo.borrarNuevosObjetosVivos();
	}
	
	private void cargarVistas(){
		this.vistaH.put("Avioneta",new VistaAvioneta());
		this.vistaH.put("AvionJugador",new VistaAvionJugador());
		this.vistaH.put("Bombardero",new VistaBombardero());
		this.vistaH.put("Caza",new VistaCaza());
		this.vistaH.put("Cohete",new VistaCohete());
		this.vistaH.put("Energia",new VistaEnergia());
		this.vistaH.put("Explorador",new VistaExplorador());
		this.vistaH.put("Laser",new VistaLaser());
		this.vistaH.put("PackDeArmamento",new VistaPackArmamento());
		this.vistaH.put("Torpedo",new VistaTorpedo());
		this.vistaH.put("TorpedoRastreador",new VistaTorpedoRastreador());
		this.vistaH.put("HelicopteroPolicia",new VistaHelicoptero());
		this.vistaH.put("AvionGuia",new VistaAvionGuia());
		this.vistaH.put("CazaNuevo",new VistaCazaNuevo());
		this.vistaH.put("TorpedoAdaptable",new VistaTorpedoAdaptable());
		this.vistaH.put("Civil",new VistaCivil());
	}
	
	public void persistir() {
		try {
			OutputStream fos = new FileOutputStream("savestate.dat");
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(modelo);			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Deserializacion
	 */
	public void levantarDatos() {
		try {
			File fichero = new File("savestate.dat");
			if(fichero.exists()){
				InputStream fis = new FileInputStream("savestate.dat");
				ObjectInputStream ois = new ObjectInputStream(fis);
				Juego.reemplazar((Juego)ois.readObject());
				modelo = Juego.singleton();	
				Juego.reemplazar(modelo);
				reestructurarElModelo();
			}
			else{
				System.exit(1);
				
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Metodo que agrega a todos los objetos del modelo a la lista
	 * de nuevosObjetosVivos, luego con cargarVistas se recupera la
	 * lista de dibujables.
	 */
	private void reestructurarElModelo() {
		modelo.agregarNuevoObjetoVivo(modelo.jugador());
		this.agregarDibujable(new VistaFondo());
		
		ControladorNivel nivel=new ControladorNivel();
		TextoDinamico niv = new TextoDinamico(nivel);
		niv.setPosicionable(nivel);
		this.agregarDibujable(niv);
		@SuppressWarnings("unchecked")
		Collection<Avion> listaClonadaAviones = (Collection<Avion>) modelo.avionesActivos().clone();
		Iterator<Avion> iteradorAviones = listaClonadaAviones.iterator();
		int n = 0;
		while (iteradorAviones.hasNext()) {
			Avion avion = iteradorAviones.next();
			modelo.agregarAvion(avion);
			n++;			
		}
		iteradorAviones = modelo.avionesActivos().iterator();
		for (int i=0; i<n; i++) {
			iteradorAviones.next();
			iteradorAviones.remove();
		}
		
		@SuppressWarnings("unchecked")
		Collection<Disparo> listaClonadaDisparosEnemigos = (Collection<Disparo>) modelo.disparosEnemigos().clone();
		Iterator<Disparo> iteradorDisparosEnemigos = listaClonadaDisparosEnemigos.iterator();
		n = 0;
		while (iteradorDisparosEnemigos.hasNext()) {
			Disparo disparo = iteradorDisparosEnemigos.next();
			modelo.agregarDisparoEnemigo(disparo);
			n++;			
		}
		iteradorDisparosEnemigos = modelo.disparosEnemigos().iterator();
		for (int i=0; i<n; i++) {
			iteradorDisparosEnemigos.next();
			iteradorDisparosEnemigos.remove();
		}
		
		@SuppressWarnings("unchecked")
		Collection<Disparo> listaClonadaDisparosJugador = (Collection<Disparo>) modelo.disparosJugador().clone();
		Iterator<Disparo> iteradorDisparosJugador = listaClonadaDisparosJugador.iterator();
		n = 0;
		while (iteradorDisparosJugador.hasNext()) {
			Disparo disparo = iteradorDisparosJugador.next();
			modelo.agregarDisparoJugador(disparo);
			n++;			
		}
		iteradorDisparosJugador = modelo.disparosJugador().iterator();
		for (int i=0; i<n; i++) {
			iteradorDisparosJugador.next();
			iteradorDisparosJugador.remove();
		}
		
		@SuppressWarnings("unchecked")
		Collection<Item> listaClonadaItems = (Collection<Item>) modelo.items().clone();
		Iterator<Item> iteradorItems = listaClonadaItems.iterator();
		n = 0;
		while (iteradorItems.hasNext()) {
			Item item = iteradorItems.next();
			modelo.agregarItem(item);
			n++;			
		}
		iteradorItems = modelo.items().iterator();
		for (int i=0; i<n; i++) {
			iteradorItems.next();
			iteradorItems.remove();
		}
	}
	
	/**
	 * Irrelevante a nivel practico, pero no sacar.
	 */
	public ControladorAlgoWing42() {
		super(false);
	}	
}
